#define _CRT_SECURE_NO_WARNINGS
#include <cstring> //for strcmp()
#include <cstdlib> // for atoi()
#include "list_of_flows.h"



Flow::Flow(char* sadd, unsigned short int sport, char* dadd,
	unsigned short int dport, unsigned short int wgt)
{
	unsigned int i;
	for (i = 0; i < strlen(sadd)+1; i++)
	{
		src_ip_add[i] = sadd[i];
	}
	for (i = 0; i < strlen(dadd) + 1; i++)
	{
		des_ip_add[i] = dadd[i];
	}
	
	src_port = sport;
	des_port = dport;
	weight = wgt;

	credit = 0;
	head_packet_queue = NULL;
	tail_packet_queue = NULL;
	next_flow = NULL;
}

Flow::~Flow()
{
	Packet* temp_pkt = head_packet_queue;
	while (temp_pkt !=NULL)
	{
		head_packet_queue = head_packet_queue->next_packet;
		delete temp_pkt;
		temp_pkt = head_packet_queue;
	}
}

bool Flow::Check_Flow(char* sadd, unsigned short int sport, char* dadd, unsigned short int dport)
{
	if (strcmp(src_ip_add, sadd) || strcmp(des_ip_add, dadd))
		return false;
	
	if (sport != src_port || dport != des_port)
		return false;
	
	return true;
}

int Flow::Add_Pkt_To_Flow(long int pktID, long int arrived_time, unsigned short int length)
{
	Packet* new_packet = NULL;
	try
	{
		new_packet = new Packet();
	}
	
	catch (std::bad_alloc& ba)
	{
		std::cerr << "bad_alloc caught: " << ba.what() << '\n';
		return 1;
	}

	new_packet->pktID = pktID;
	new_packet->arrive_time = arrived_time;
	new_packet->length = length;
	new_packet->next_packet = NULL;

	if (head_packet_queue == NULL) // empty queue case
	{
		head_packet_queue = new_packet;
		tail_packet_queue = new_packet;
	}
	else // add the new packet to end of the queue
	{
		tail_packet_queue->next_packet = new_packet;
		tail_packet_queue = new_packet;
	}
	return 0;
}

long int Flow::Remove_Pkt_From_Flow(long int time, FILE* outfile_p)
{
	
	if (head_packet_queue == NULL) // empty queue case
		return 0; // there is no packet to remove form this flow
	else
	{
		char buffer[BUF_SIZE];
		if (sprintf(buffer, "%ld: %ld\n",
			time, head_packet_queue->pktID) < 0)
		{
			cerr << "Sprintf failed.\n";
			return -1;

		}
		else
		{
			long int departure_time = time + head_packet_queue->length;
			Packet* temp_pkt = head_packet_queue;
			head_packet_queue = head_packet_queue->next_packet;
			if (head_packet_queue == NULL) // delete the last packet
				tail_packet_queue = NULL;
			delete temp_pkt;
			if (fwrite(buffer, sizeof(char), strlen(buffer) , outfile_p) < strlen(buffer))
			{
				cerr << "Fwrite() failed.\n";
				return -1;
			}
			return departure_time;
		}	
			
	}
}

unsigned short int Flow::Get1PacketLength()
{
	if (head_packet_queue == NULL)
		return 0;
	else
		return head_packet_queue->length;
}


unsigned short int Flow::getWeight()
{
	return weight;
}

void Flow::AddCredit(int quantum)
{
	if ((credit > 0) && (Get1PacketLength() == 0)) //allready got credit but still no packet => zerorize
		ZerorizeCredit();
	else if (Get1PacketLength() > 0)
		credit += weight*quantum;
}

void Flow::ReduceCredit()
{
	credit -= Get1PacketLength();
}

int Flow::GetCredit()
{
	return credit;
}

void Flow::ZerorizeCredit()
{
	credit = 0;
}